package com.wtx.fitness.exception;

import com.wtx.fitness.common.Result;
import com.wtx.fitness.common.ResultCode;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.sql.SQLIntegrityConstraintViolationException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 全局异常处理器
 * 统一处理各种异常，返回标准格式的响应
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

  /**
   * 处理参数校验异常
   */
  @ExceptionHandler(MethodArgumentNotValidException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public Result<Void> handleValidationExceptions(MethodArgumentNotValidException ex) {
    BindingResult bindingResult = ex.getBindingResult();
    List<FieldError> fieldErrors = bindingResult.getFieldErrors();
    String errorMessage = fieldErrors.stream()
        .map(error -> error.getField() + ": " + error.getDefaultMessage())
        .collect(Collectors.joining(", "));

    return Result.failure(ResultCode.PARAM_ERROR, "参数验证失败: " + errorMessage);
  }

  /**
   * 处理表单绑定异常
   */
  @ExceptionHandler(BindException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public Result<Void> handleBindExceptions(BindException ex) {
    BindingResult bindingResult = ex.getBindingResult();
    List<FieldError> fieldErrors = bindingResult.getFieldErrors();
    String errorMessage = fieldErrors.stream()
        .map(error -> error.getField() + ": " + error.getDefaultMessage())
        .collect(Collectors.joining(", "));

    return Result.failure(ResultCode.PARAM_ERROR, "参数绑定失败: " + errorMessage);
  }

  /**
   * 处理唯一约束违反异常（主要用于处理学号等唯一值重复的情况）
   */
  @ExceptionHandler({ DuplicateKeyException.class, SQLIntegrityConstraintViolationException.class })
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public Result<Void> handleDuplicateKeyException(Exception ex) {
    String message = ex.getMessage();
    if (message.contains("Duplicate entry")) {
      // 解析MySQL错误信息中的重复值
      String duplicateValue = extractDuplicateValue(message);
      if (message.contains("student.PRIMARY") || message.contains("UK_student_stu_id")) {
        return Result.failure(ResultCode.PARAM_ERROR, "学号 " + duplicateValue + " 已存在");
      }
    } else if (message.contains("foreign key constraint") || message.contains("FOREIGN KEY")) {
      // 外键约束违反 - 有可能是学生被删除时有关联的成绩记录
      if (message.contains("score") || message.contains("stu_id")) {
        return Result.failure(
            ResultCode.OPERATION_CONFLICT,
            "该学生有关联的体测成绩，删除学生将同时删除其所有成绩记录。请确认是否要删除？");
      }
    }
    return Result.failure(ResultCode.PARAM_ERROR, "数据已存在或有关联数据限制");
  }

  /**
   * 处理业务异常
   */
  @ExceptionHandler(BusinessException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public Result<Void> handleBusinessException(BusinessException ex) {
    return Result.failure(ex.getCode(), ex.getMessage());
  }

  /**
   * 处理未授权异常
   */
  @ExceptionHandler(UnauthorizedException.class)
  @ResponseStatus(HttpStatus.UNAUTHORIZED)
  public Result<Void> handleUnauthorizedException(UnauthorizedException ex) {
    return Result.failure(ResultCode.UNAUTHORIZED, ex.getMessage());
  }

  /**
   * 处理资源未找到异常
   */
  @ExceptionHandler(NotFoundException.class)
  @ResponseStatus(HttpStatus.NOT_FOUND)
  public Result<Void> handleNotFoundException(NotFoundException ex) {
    return Result.failure(ResultCode.NOT_FOUND, ex.getMessage());
  }

  /**
   * 处理其他所有未明确处理的异常
   */
  @ExceptionHandler(Exception.class)
  @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
  public Result<Void> handleAllExceptions(Exception ex) {
    ex.printStackTrace(); // 服务器端记录异常堆栈
    return Result.failure(ResultCode.SYSTEM_ERROR, "系统错误: " + ex.getMessage());
  }

  /**
   * 从MySQL错误信息中提取重复值
   */
  private String extractDuplicateValue(String message) {
    try {
      // 错误格式: Duplicate entry 'value' for key 'keyname'
      int startIndex = message.indexOf("'") + 1;
      int endIndex = message.indexOf("'", startIndex);
      if (startIndex > 0 && endIndex > startIndex) {
        return message.substring(startIndex, endIndex);
      }
    } catch (Exception e) {
      // 解析失败，忽略
    }
    return "未知值";
  }
}